package userandright

import (
	"os"
	"strings"

	"gitee.com/tomatomeatman/golang-repository/bricks2/function/data/jsonutil"
	"gitee.com/tomatomeatman/golang-repository/bricks2/function/fileutil"
	"gitee.com/tomatomeatman/golang-repository/bricks2/model/msgentity"
	"gitee.com/tomatomeatman/golang-repository/bricks2/utils/app"
	"gitee.com/tomatomeatman/golang-repository/bricks2/utils/ginutil"

	"gitee.com/tomatomeatman/golang-repository/bricks2/utils/gorm"
	Log "github.com/cihub/seelog"
)

type UserAndRightService struct {
	app.ServiceBaseFunc
}

var (
	cUserRightCacheOrdinary = make(map[string][]string) //用户权限验证用缓存池(普通)
	cUserRightCacheSpecial  = make(map[string][]string) //用户权限验证用缓存池(特殊)
	sDbName                 string                      //数据库名
)

func init() {
	sDbName = app.ReadConfigKey("DbVariables", "", "").(string)
	//IgnoreUrlService{}.initCacheMap() //初始化缓存
}

/**
 * 验证指定用户是否有访问指定url的权限
 * @param UserId 验证的用户
 * @param url 请求验证的权限(URL地址)
 * @return
 */
func (service UserAndRightService) CheckRight(ctx ginutil.Context, UserId, url string) *msgentity.MsgEntity {
	if UserId == "" {
		return msgentity.Err(8001, "待验证的用户编号为空")
	}

	if url == "" {
		return msgentity.Err(8002, "待验证的访问权限为空")
	}

	urlOrdinary := ";" + url + ";" //添加前后缀以免误判

	//--先判断普通权限,普通权限的前后都加有';'--//
	list, ok := cUserRightCacheOrdinary[UserId]
	if !ok {
		filePath := "./temp/cache/UserAndRight/" + UserId + "_UrlOrdinary.txt"
		bl, _, data := jsonutil.FormFile(filePath, []string{})
		if bl {
			cUserRightCacheOrdinary[UserId] = data.([]string)
			list, ok = cUserRightCacheOrdinary[UserId] //再判断一次
		}
	}

	if ok && (len(list) > 0) {
		for _, val := range list {
			if strings.Contains(val, urlOrdinary) {
				return msgentity.Success(8999, "有权限")
			}
		}
	}

	if len(list) < 1 {
		me := service.LoadRight(UserId) //读取指定用户的权限
		if !me.Success {
			return me
		}

		b := false
		array := []string{}
		simplRights := me.Data.([]SimpleRight)
		for _, simplRight := range simplRights {
			if simplRight.ControllerPath == "" {
				continue
			}

			temp := strings.Split(simplRight.ControllerPath, ";")
			for _, v := range temp {
				if (v == "") || strings.Contains(v, "*") {
					continue
				}

				v = ";" + v + ";"
				array = append(array, v)
				if strings.Contains(v, urlOrdinary) {
					b = true
				}
			}
		}

		Array, ok := cUserRightCacheOrdinary[UserId]
		if ok {
			Array = append(Array, array...)

			cUserRightCacheOrdinary[UserId] = Array
		} else {
			cUserRightCacheOrdinary[UserId] = array
		}

		if b {
			return msgentity.Success(8999, "有权限")
		}
	}

	//--普通权限没有则查找通配符方式,通配符方式权限的前后没有加';'--//
	urlOrdinary = url //重新回到URL
	list, ok = cUserRightCacheSpecial[UserId]
	if !ok {
		filePath := "./temp/cache/UserAndRight/" + UserId + "_UrlSpecial.txt"
		bl, _, data := jsonutil.FormFile(filePath, []string{})
		if bl {
			cUserRightCacheSpecial[UserId] = data.([]string)
			list, ok = cUserRightCacheSpecial[UserId] //再判断一次
		}
	}

	if ok && (len(list) > 0) {
		for _, val := range list {
			if strings.HasPrefix(urlOrdinary, val) { //判断是否以'val'为开头
				return msgentity.Success(8999, "有权限")
			}
		}
	}

	if len(list) < 1 {
		me := service.LoadRight(UserId) //读取指定用户的权限
		if !me.Success {
			return me
		}

		b := false
		array := []string{}
		simplRights := me.Data.([]SimpleRight)
		for _, simplRight := range simplRights {
			if simplRight.ControllerPath == "" {
				continue
			}

			temp := strings.Split(simplRight.ControllerPath, ";")
			for _, v := range temp {
				if (v == "") || !strings.Contains(v, "*") {
					continue
				}

				iEd := strings.Index(v, "*")
				array = append(array, v[:iEd])
				if strings.HasPrefix(urlOrdinary, v) {
					b = true
				}
			}
		}

		Array, ok := cUserRightCacheSpecial[UserId]
		if ok {
			Array = append(Array, array...)

			cUserRightCacheSpecial[UserId] = Array
		} else {
			cUserRightCacheSpecial[UserId] = array
		}

		cUserRightCacheSpecial[UserId] = array

		if b {
			return msgentity.Success(8999, "有权限")
		}
	}

	return msgentity.Err(8004, "无权权访问:", url)
}

/**
 * 读取指定用户的权限,并返回权限集合
 * @param UserId
 * @return
 */
func (service UserAndRightService) LoadRight(UserId string) *msgentity.MsgEntity {
	//--读文件获取--//
	filePath := "./temp/cache/UserAndRight/" + UserId + "_Simpl.txt"
	//CacheTxtUtil{}.ReadCacheFile(result, filePath)
	//temp := CacheTxtUtil{}.ReadCacheFile(filePath)
	bl, _, data := jsonutil.FormFile(filePath, SimpleRight{})
	if bl {
		list := data.([]SimpleRight)
		service.crateRightCache(list, UserId)
		return msgentity.Success(list, "在文件中找到") //返回结果
	}

	//--文件没有则读库获取--//
	me := service.findRightListByInit(UserId) //根据用户读取用户对应的所有权限,注意:只返回了3个值RightId/sEnglish/sControllerPath
	if !me.Success {
		return me
	}

	list := me.Data.([]SimpleRight)
	if len(list) < 1 {
		return msgentity.Err(8100, "未查询到用户相关权限信息!")
	}

	service.crateRightCache(list, UserId)

	//CacheTxtUtil{}.CreateCacheFile(list, "./temp/cache/UserAndRight/"+UserId+"_Simpl.txt") //写入文件，以便下次不用读库
	jsonutil.ToFile(list, "./temp/cache/UserAndRight/"+UserId+"_Simpl.txt")

	return msgentity.Success(list, "在数据库中找到") //返回结果
}

/**
 * 初始化查询权限信息集合
 * @param UserId
 * @return
 */
func (service UserAndRightService) findRightListByInit(userId string) *msgentity.MsgEntity {
	var build strings.Builder
	build.WriteString(" SELECT")
	build.WriteString(" 	right_manage.right_id,")
	build.WriteString(" 	right_manage.english,")
	build.WriteString(" 	right_manage.urls as controller_path")
	build.WriteString(" FROM ")

	where := map[string]interface{}{}

	if (userId != "") && (strings.Contains("/00000000/00000001/", userId)) {
		build.WriteString(" 	${BaseSystem}right_manage")
	} else {
		build.WriteString(" 	${BaseSystem}right_manage AS a, ${BaseSystem}user_and_right")
		build.WriteString(" WHERE right_manage.right_id = user_and_right.right_id")
		build.WriteString(" 	AND user_and_right.user_id = @userId ")
		build.WriteString(" UNION")
		build.WriteString(" SELECT ")
		build.WriteString(" 	right_manage.right_id,")
		build.WriteString(" 	right_manage.english,")
		build.WriteString(" 	right_manage.urls as controller_path ")
		build.WriteString(" FROM ${BaseSystem}right_manage")
		build.WriteString(" WHERE right_manage.right_id IN (")
		build.WriteString(" 	select right_id from ${BaseSystem}role_and_right")
		build.WriteString(" 	where role_and_right.role_id in (")
		build.WriteString(" 		select a.role_id from ${BaseSystem}user_and_role a")
		build.WriteString(" 		where a.user_id = @userId")
		build.WriteString(" 	)")
		build.WriteString(" )")

		where["userId"] = userId
	}

	txt := build.String()
	txt = strings.Replace(txt, "${BaseSystem}", sDbName, -1)

	list := []SimpleRight{}
	dbResult := gorm.Raw(txt, where).Find(&list)

	if dbResult.Error != nil {
		Log.Error("查询发生异常:", dbResult.Error)
		return msgentity.Err(1002, "查询数据发生异常:", dbResult.Error)
	}

	return msgentity.Success(list, "新增成功")
}

/**
 * 创建缓存
 */
func (service UserAndRightService) crateRightCache(list []SimpleRight, UserId string) *msgentity.MsgEntity {
	if len(list) < 1 {
		return msgentity.Err(8100, "数据有错")
	}

	var sbEnglist strings.Builder
	listRightId := map[string]string{}
	listUrlsOrdinary := map[string]string{}
	listUrlsSpecial := map[string]string{}

	for _, simpleRight := range list {
		sbEnglist.WriteString(simpleRight.English)
		sbEnglist.WriteString("/")
		listRightId[simpleRight.RightId] = ""

		temp := strings.TrimSpace(simpleRight.ControllerPath)
		if temp == "" {
			continue
		}

		array := strings.Split(temp, ";")
		for _, val := range array {
			val = strings.TrimSpace(val)
			if (val == "") || (val == "-") {
				continue
			}

			str := ";" + val + ";"
			_, ok := listUrlsOrdinary[str]
			if (!strings.Contains(val, "*")) && (!ok) {
				listUrlsOrdinary[str] = ""
				continue
			}

			_, ok = listUrlsSpecial[val]
			if (strings.Contains(val, "*")) && (!ok) {
				iEd := strings.Index(val, "*")
				listUrlsSpecial[val[:iEd]] = ""
				continue
			}
		}
	}

	array := []string{}
	for key := range listUrlsOrdinary {
		array = append(array, key)
	}
	//CacheTxtUtil{}.CreateCacheFile(array, "./temp/cache/UserAndRight/"+UserId+"_UrlOrdinary.txt") //写入文件，以便下次不用读库
	jsonutil.ToFile(array, "./temp/cache/UserAndRight/"+UserId+"_UrlOrdinary.txt")

	array = []string{}
	for key := range listUrlsSpecial {
		array = append(array, key)
	}
	//CacheTxtUtil{}.CreateCacheFile(array, "./temp/cache/UserAndRight/"+UserId+"_UrlSpecial.txt") //写入文件，以便下次不用读库
	jsonutil.ToFile(array, "./temp/cache/UserAndRight/"+UserId+"_UrlSpecial.txt")

	array = []string{}
	for key := range listRightId {
		array = append(array, key)
	}
	//CacheTxtUtil{}.CreateCacheFile(array, "./temp/cache/UserAndRight/"+UserId+"_UserRightIdList.txt") //写入文件，以便下次不用读库
	jsonutil.ToFile(array, "./temp/cache/UserAndRight/"+UserId+"_UserRightIdList.txt")

	fileutil.Save(sbEnglist.String(), "./temp/cache/UserAndRight/"+UserId+"_Englist.txt") //写入文件，以便下次不用读库

	return msgentity.Success(8999, "创建缓存成功") //返回结果
}

/**
 * 根据用户查询用户所拥有的权限的最后更新时间
 * @param UserId
 * @return
 */
func (service UserAndRightService) LastTime(ctx ginutil.Context, UserId string) *msgentity.MsgEntity {
	UserId = strings.TrimSpace(UserId)
	if UserId == "" {
		return msgentity.Err(8001, "待验证的用户编号为空")
	}

	//--读文件获取--//
	filePath := "./temp/cache/UserAndRight/" + UserId + "_Simpl.txt"
	if fileutil.IsExist(filePath) {
		f, _ := os.Open(filePath)
		fi, _ := f.Stat()
		return msgentity.Success(fi.ModTime().Unix(), "查询到权限信息缓存最后时间")
	}

	service.LoadRight(UserId) //建立缓存

	if fileutil.IsExist(filePath) {
		f, _ := os.Open(filePath)
		fi, _ := f.Stat()
		return msgentity.Success(fi.ModTime().Unix(), "查询到权限信息缓存最后时间")
	}

	return msgentity.Err(8002, "没有查询到权限信息缓存最后时间")
}

/**
 * 根据用户查询用户所拥有的权限编号集合
 * @param UserId
 * @return
 */
func (service UserAndRightService) FindRightId(UserId string) *msgentity.MsgEntity {
	UserId = strings.TrimSpace(UserId)
	if UserId == "" {
		return msgentity.Err(8001, "用户编号不能为空")
	}

	//-- 读取预存储的缓存文件 --//
	filePath := "./temp/cache/UserAndRight/" + UserId + "_UserRightIdList.txt"
	bl, _, data := fileutil.ReadFromFile(filePath)
	if bl {
		array := strings.Split(data.(string), ",")
		if len(array) > 0 {
			return msgentity.Success(array, "查询成功")
		}
	}

	me := service.LoadRight(UserId) //读取指定用户的权限
	if !me.Success {
		return me
	}

	bl, msg, data := fileutil.ReadFromFile(filePath)
	if !bl {
		return msgentity.Err(data.(int)+10, msg)
	}

	array := strings.Split(me.Data.(string), ",")

	return msgentity.Success(array, "查询成功")
}

/**
 * 根据用户取权限标识字符串(一个权限标识代表了多个可访问的url路径)
 * @param UserId
 * @return
 */
func (service UserAndRightService) FindEnglishByUserId(UserId string) *msgentity.MsgEntity {
	UserId = strings.TrimSpace(UserId)
	if UserId == "" {
		return msgentity.Err(8001, "用户编号不能为空")
	}

	//-- 读取预存储的缓存文件 --//
	filePath := "./temp/cache/UserAndRight/" + UserId + "_Englist.txt"
	bl, _, data := fileutil.ReadFromFile(filePath)
	if bl {
		if data.(string) != "" {
			return msgentity.Success(data.(string), "查询成功")
		}
	}

	me := service.LoadRight(UserId) //读取指定用户的权限
	if !me.Success {
		return me
	}

	bl, msg, data := fileutil.ReadFromFile(filePath)
	if !bl {
		return msgentity.Err(data.(int)+10, msg)
	}

	if data.(string) == "" {
		return msgentity.Err(8002, "没有找到用户对应的权限")
	}

	return msgentity.Success(me.Data.(string), "查询成功")
}
